<template>
  <Editor :id="tinymceId" v-model="modelValue" :init="init" :disabled="disabled" />
</template>

<script setup lang="ts">
import tinymce from 'tinymce/tinymce'
import Editor from '@tinymce/tinymce-vue'
import 'tinymce/skins/content/default/content.css'
import 'tinymce/themes/silver'
import 'tinymce/themes/silver/theme'
import 'tinymce/icons/default' // 图标icon
import 'tinymce/icons/default/icons'
import 'tinymce/models/dom' // 这里是个坑 一定要引入

// 相关插件
import 'tinymce/plugins/image' // 插入上传图片插件
import 'tinymce/plugins/table' // 插入表格插件
import 'tinymce/plugins/lists' // 列表插件
import 'tinymce/plugins/wordcount' // 字数统计插件
import 'tinymce/plugins/code' // 源码
import 'tinymce/plugins/media' // 插入视频插件
import 'tinymce/plugins/fullscreen' // 全屏

import { baseDefaultConfig } from './config'
import { reactive } from 'vue'
import { defineModel, defineProps, onMounted } from 'vue'

interface MediaSource {
  source: string
  sourcemime: string
}

type EditorInit = (typeof tinymce)['defaultOptions']

const modelValue = defineModel<string>()
const props = defineProps<{
  /** 禁用 */
  disabled?: boolean
  /** 高度 */
  height?: number
  /** 上传 */
  upload: (file: Blob | File, fileName: string) => Promise<string>
}>()

// 富文本编辑器id
const tinymceId = 'vue-tinymce-' + (Math.random() * 1000).toFixed(0)

// init初始化
const init = reactive<EditorInit>({
  selector: '#' + tinymceId,
  height: props.height || 800, // 编辑器高度
  ...baseDefaultConfig,
  video_template_callback: (data: MediaSource) => {
    return `<video width="745" height="420" controls="controls" src=${data.source} />`
  },
  file_picker_callback: (callback, _, meta) => {
    if (meta.filetype === 'media') {
      upLoadVideo()
        .then((res) => {
          callback(res)
        })
        .catch(() => {
          callback('')
        })
    } else {
      callback('')
    }
  },
  // 图片上传
  images_upload_handler: async (blobInfo) => {
    if (blobInfo.blob().size / 1024 / 1024 > 5119) {
      return Promise.reject('上传失败，图片大小请控制在 5G 以内')
    }
    const fileName = blobInfo.filename()
    const url = await props.upload(blobInfo.blob(), fileName)
    return url
  }
})

/**
 * 上传音视频媒体
 */
function upLoadVideo(): Promise<string> {
  return new Promise((resolve, reject) => {
    const input = document.createElement('input')
    input.setAttribute('type', 'file')
    input.setAttribute('accept', '.mp4,.mp3')
    input.onchange = async () => {
      const file = input.files?.[0]
      if (!file || (!file.type.includes('video') && !file.type.includes('audio'))) {
        reject()
        return
      }
      const fileName = file.name
      props.upload(file, fileName)
        .then((url) => {
          resolve(url)
        })
        .catch(() => {
          reject()
        })
    }
    input.click()
  })
}

onMounted(() => {
  tinymce.init({})
})
</script>

<style>
body {
  margin: 0;
}

.tox-textarea-wrap {
  flex: 1;
  display: flex;
  flex-direction: column;
}

.tox{z-index:9999!important;}
</style>
